﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Kugar.Core.BaseStruct;
using Kugar.Core.Collections;
using Kugar.Core.ExtMethod;

namespace Kugar.Core.Provider.TreeDataProvider
{
    public class Tree_XMLDataProvider : ITree_DataProvider
    {
        private XmlDocument _document = null;
        private string _filePath = "";
        private bool _isAutoSync = false;

        public Tree_XMLDataProvider(string filePath)
        {
            _filePath = filePath;
            _document = new XmlDocument();
            if (File.Exists(_filePath))
            {
                _document.Load(_filePath);
            }
            else
            {
                var root = _document.CreateNode(XmlNodeType.Element, "root", "");

                _document.AppendChild(root);
            }

        }


        #region Implementation of ITree_DataProvider

        public bool Add(TreeNodeForStorage item)
        {
            if (string.IsNullOrWhiteSpace(item.Key))
            {
                throw new ArgumentOutOfRangeException("item.Key");
            }

            var node = _document.SelectSingleNode(string.Format("//Node[@Key='{0}']", item.ParentKey.ToStringEx()));

            if (node == null)
            {
                return false;
            }

            var newNode = _document.CreateElement("Node");

            newNode.SetAttribute("ParentKey", item.ParentKey.ToStringEx());
            newNode.SetAttribute("Text", item.Text.ToStringEx());
            newNode.SetAttribute("Value", item.Value);
            newNode.SetAttribute("Key", item.Key);
            newNode.SetAttribute("Path", item.Path);

            node.AppendChild(newNode);

            if (_isAutoSync)
            {
                try
                {
                    saveToFile();
                    return true;
                }
                catch (Exception)
                {
                    return false;
                }
            }
            else
            {
                return true;
            }

        }

        public bool Update(TreeNodeForStorage item)
        {
            //var node = _document.GetElementById(item.ParentKey);
            var node = _document.SelectSingleNode(string.Format("//Node[@Key='{0}']", item.Key));

            if (node == null)
            {
                return false;
            }

            if (node.Attributes.GetStringByName("ParentKey") != item.ParentKey)
            {
                var newParent = _document.SelectSingleNode(string.Format("//Node[@Key='{0}']", item.ParentKey));

                if (newParent == null)
                {
                    throw new ArgumentOutOfRangeException("item.ParentKey");
                }

                node.ParentNode.RemoveChild(node);

                newParent.AppendChild(node);
            }

            node.Attributes["ParentKey"].Value = item.ParentKey;
            //node.Attributes["Key"].Value=item.Key;
            node.Attributes["Text"].Value = item.Text;
            node.Attributes["Value"].Value = item.Value;
            node.Attributes["Path"].Value = item.Path;

            if (_isAutoSync)
            {
                try
                {
                    saveToFile();
                    return true;
                }
                catch (Exception)
                {
                    return false;
                }
            }
            else
            {
                return true;
            }
        }

        public bool Delete(string key)
        {
            var node = _document.SelectSingleNode(string.Format("//Node[@Key='{0}']", key));
            //var n=_document.GetElementById(key);

            if (node == null)
            {
                return false;
            }

            var p = node.ParentNode ?? _document;

            p.RemoveChild(node);

            if (_isAutoSync)
            {
                try
                {
                    saveToFile();
                    return true;
                }
                catch (Exception)
                {
                    return false;
                }
            }
            else
            {
                return true;
            }
        }

        public void Save(Tree srcTree)
        {
            _document = ToXML(srcTree);

            //_document = doc;

            saveToFile();
        }

        public void LoadTree(Tree targetTree)
        {
            var treeRoot = targetTree.Nodes[0];
            var xmlRoot = _document.ChildNodes[0];

            buildTreeNode(xmlRoot, treeRoot);
        }


        public IList<TreeNodeForStorage> GetChildCategoryByPath(string path)
        {
            //_document.SelectNodes("//Node[@Path]")
            return null;
        }

        public IList<TreeNodeForStorage> GetChildCategory(string parentKey)
        {
            //_document.
            return null;
        }

        #endregion

        private void buildXMLNode(XmlNode parent, TreeNode parentNode, XmlDocument document)
        {
            foreach (var treenode in parentNode.Nodes)
            {
                var xmlNode = document.CreateNode(XmlNodeType.Element, "Node", "");
                var nameAttribute = document.CreateAttribute("Text");
                var keyAttribute = document.CreateAttribute("Key");
                var valueAttribute = document.CreateAttribute("Value");

                nameAttribute.Value = treenode.Text;
                keyAttribute.Value = treenode.Key;
                valueAttribute.Value = treenode.Value.SerializeToString();


                xmlNode.Attributes.Append(nameAttribute);
                xmlNode.Attributes.Append(keyAttribute);
                xmlNode.Attributes.Append(valueAttribute);

                parent.AppendChild(xmlNode);
                if (!treenode.IsLeaf)
                {
                    buildXMLNode(xmlNode, treenode, document);
                }
            }
        }

        private void buildTreeNode(XmlNode node, TreeNode parentNode)
        {
            foreach (XmlNode xmlNode in node.ChildNodes)
            {
                var treeNode = parentNode.Tree.CreateNode();// new TreeNode();

                treeNode.Text = xmlNode.Attributes.GetStringByName("Text");
                treeNode.Key = xmlNode.Attributes.GetStringByName("Key");
                treeNode.Value = xmlNode.Attributes.GetStringByName("Value").DeserializeToObject();

                parentNode.Nodes.Add(treeNode);

                if (!xmlNode.HasChildNodes)
                {
                    if (!string.IsNullOrWhiteSpace(xmlNode.InnerText))
                    {
                        treeNode.Value = SerialObjectExt.DeserializeToObject(xmlNode.InnerText.ToStringEx());
                    }
                }
                else
                {
                    buildTreeNode(xmlNode, treeNode);
                }

            }

        }

        private void saveToFile()
        {
            _document.Save(_filePath);
        }

        private XmlDocument ToXML(Tree tree)
        {
            XmlDocument document = new XmlDocument();

            var root = document.CreateNode(XmlNodeType.Element, "root", "");

            document.AppendChild(root);

            buildXMLNode(root, tree.Nodes[0], document);

            return document;
        }

        private TreeNodeForStorage xmlNodeToTreeNodeStorage(XmlNode xmlNode)
        {
            var temp = new TreeNodeForStorage();

            temp.Key = xmlNode.Attributes.GetStringByName("Key");
            temp.ParentKey = xmlNode.Attributes.GetStringByName("ParentKey");
            temp.Text = xmlNode.Attributes.GetStringByName("Text");
            temp.Value = xmlNode.Attributes.GetStringByName("Value");

            return temp;

        }
    }
}
